/*
 * DShowGraph.cpp
 *
 *  Created on: 2011-8-5
 *      Author: terry
 */

#include "DShowGraph.h"
#include "GraphUtil.h"
#include "CommonMacro.h"
#include <dvdmedia.h>
#include "PixelFormat.h"



DShowGraph::DShowGraph() :
	m_rotCookie(0),
	m_graphBuilder(NULL),
	m_mediaControl(NULL),
    m_captureBuilder2(NULL),
    m_pSampleCallBack(NULL)
{

}

DShowGraph::~DShowGraph()
{

}

void DShowGraph::setSampleCallBack(av::SampleCallBack* pCB)
{
    m_pSampleCallBack = pCB;
}










HRESULT DShowGraph::initGraph()
{
	HRESULT hr = S_OK;

    hr = ::CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
		    IID_IGraphBuilder, (LPVOID *)&m_graphBuilder);
    CheckPointer(m_graphBuilder, hr);

    hr = CoCreateInstance((REFCLSID)CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, 
		    (REFIID)IID_ICaptureGraphBuilder2,(void **)&m_captureBuilder2);
	FAILED_RETURN(hr);
	hr = m_captureBuilder2->SetFiltergraph(m_graphBuilder);


    hr = GraphUtil::addGraphToRot(m_graphBuilder, &m_rotCookie);

    hr = m_graphBuilder->QueryInterface(IID_IMediaControl,
                (void **)&m_mediaControl);

    return hr;
}

void DShowGraph::uninitGraph()
{

    GraphUtil::removeGraphFromRot(m_rotCookie);
    m_rotCookie = 0;

    SAFE_RELEASE(m_mediaControl);
    SAFE_RELEASE(m_graphBuilder);
    SAFE_RELEASE(m_captureBuilder2);
}


HRESULT DShowGraph::playGraph()
{
	CheckPointer(m_mediaControl, E_POINTER);
    return m_mediaControl->Run();
}

HRESULT DShowGraph::pauseGraph()
{
	CheckPointer(m_mediaControl, E_POINTER);
    return m_mediaControl->Pause();
}

HRESULT DShowGraph::stopGraph()
{
	CheckPointer(m_mediaControl, E_POINTER);
    return m_mediaControl->Stop();
}




bool DShowGraph::supportMediaSubType(const GUID& guid)
{
	int csp = mediaSubTypeToColorSpace(guid);
	return (csp != av::PixelFormat::kNONE);
}

int DShowGraph::mediaSubTypeToColorSpace(const GUID& guid)
{
	int csp = av::PixelFormat::kNONE;
	if (guid == MEDIASUBTYPE_UYVY)
	{
		csp = av::PixelFormat::kUYVY;
	}
	else if (guid == MEDIASUBTYPE_YUY2)
	{
		csp = av::PixelFormat::kYUY2;
	}
	else if (guid == MEDIASUBTYPE_YUYV)
	{
		csp = av::PixelFormat::kYUY2;
	}
	else if (guid == MEDIASUBTYPE_YV12)
	{
		csp = av::PixelFormat::kYV12;
	}
	else if (guid == MEDIASUBTYPE_IYUV)
	{
		csp = av::PixelFormat::kI420;
	}
	else if (guid == MEDIASUBTYPE_RGB24)
	{
		csp = av::PixelFormat::kBGR;
	}
	else if (guid == MEDIASUBTYPE_RGB32)
	{
		csp = av::PixelFormat::kRGB32;
	}
	else
	{
		csp = av::PixelFormat::kNONE;
	}
	return csp;
}


int DShowGraph::querySampleMediaFormat(ISampleGrabber* pGrabber, av::MediaFormat& fmt)
{
    if (!pGrabber)
    {
        return ERROR_INVALID_PARAMETER;
    }

    AM_MEDIA_TYPE mediaType;
	memset(&mediaType, 0, sizeof(mediaType));
    HRESULT hr = pGrabber->GetConnectedMediaType(&mediaType);
    if (FAILED(hr))
    {
        return hr;
    }

    int code = 0;
    if (mediaType.formattype == FORMAT_VideoInfo)
	{
        int colorSpace = mediaSubTypeToColorSpace(mediaType.subtype);

        const char* strColor = av::PixelFormat::getName(colorSpace);
        fmt.setVideoProp(strColor, strlen(strColor));

        fmt.m_profile = colorSpace;

		VIDEOINFOHEADER* pHeader = (VIDEOINFOHEADER*)mediaType.pbFormat;
		if (pHeader)
		{
			fmt.m_width = pHeader->bmiHeader.biWidth;
			fmt.m_height = pHeader->bmiHeader.biHeight;
            if (pHeader->AvgTimePerFrame != 0)
            {
                fmt.m_framerate = (int)(10000000LL / pHeader->AvgTimePerFrame);
            }
            else
            {
                fmt.m_framerate = 25;
            }
            fmt.m_codec = av::MEDIA_CODEC_RAW;

		}
	}
	else if (mediaType.formattype == FORMAT_VideoInfo2)
	{
		VIDEOINFOHEADER2* pHeader = (VIDEOINFOHEADER2*)mediaType.pbFormat;
		if (pHeader)
		{
			fmt.m_width = pHeader->bmiHeader.biWidth;
			fmt.m_height = pHeader->bmiHeader.biHeight;
			fmt.m_framerate = (int)(10000000LL / pHeader->AvgTimePerFrame);
			fmt.m_codec = av::MEDIA_CODEC_RAW;

		}
	}
    else if (mediaType.formattype == FORMAT_WaveFormatEx)
	{
		WAVEFORMATEX* pWave = (WAVEFORMATEX*)mediaType.pbFormat;
		if (pWave)
		{
			fmt.m_sampleRate = pWave->nSamplesPerSec;
			fmt.m_channels = pWave->nChannels;
			fmt.m_bitrate = pWave->nAvgBytesPerSec * 8;
			fmt.m_sampleBits = pWave->wBitsPerSample;
			fmt.m_audioCodec = av::MEDIA_CODEC_RAW;

			if (pWave->wBitsPerSample == 8)
			{
				fmt.m_audioProfile = 0;
			}
			else if (pWave->wBitsPerSample == 16)
			{
				fmt.m_audioProfile = 1;
			}
			else
			{

			}
		}
	}
    else
    {
        code = ERROR_INVALID_PARAMETER;
    }
    
    freeMediaType(&mediaType);

	return code;
}

void DShowGraph::freeMediaType(AM_MEDIA_TYPE* pType)
{
	AM_MEDIA_TYPE& mt = *pType;
	if (mt.cbFormat != 0) {
        CoTaskMemFree((PVOID)mt.pbFormat);

        // Strictly unnecessary but tidier
        mt.cbFormat = 0;
        mt.pbFormat = NULL;
    }
    if (mt.pUnk != NULL) {
        mt.pUnk->Release();
        mt.pUnk = NULL;
    }
}

HRESULT DShowGraph::removeFilter(IBaseFilter* pFilter)
{
    CheckPointer(m_graphBuilder, E_POINTER);
    return m_graphBuilder->RemoveFilter(pFilter);
}

void DShowGraph::removeAllFilters()
{
    GraphUtil::removeAllFilters(m_graphBuilder);
}

bool DShowGraph::isValid() const
{
    return (m_graphBuilder != NULL);
}

HRESULT DShowGraph::addFilter(IBaseFilter* pFilter, LPCWSTR wszName)
{
    CheckPointer(m_graphBuilder, E_POINTER);

    return m_graphBuilder->AddFilter(pFilter, wszName);
}

HRESULT DShowGraph::addFilter(const CLSID clsid, LPCWSTR wszName, IBaseFilter** ppFilter)
{
    IBaseFilter* pFilter = NULL;
    HRESULT hr = GraphUtil::createFilter(clsid, &pFilter);
    if (pFilter)
    {
        hr = addFilter(pFilter, wszName);

        if (ppFilter)
        {
            *ppFilter = pFilter;
        }
        else
        {
            SAFE_RELEASE(pFilter);
        }
    }
    return hr;
}

FILTER_STATE DShowGraph::getGraphState()
{
	FILTER_STATE	state = State_Stopped;
	if ( m_mediaControl != NULL )
	{
		m_mediaControl->GetState(500,(OAFilterState*)&state);
	}
	return state;
}

HRESULT DShowGraph::findFilterByName(LPCWSTR wszName,IBaseFilter** ppFilter)
{
    return m_graphBuilder->FindFilterByName(wszName, ppFilter);
}

HRESULT DShowGraph::showVideoWnd(bool show)
{
    CheckPointer(m_graphBuilder, E_POINTER);

    IVideoWindow* pVideoWindow = NULL;
    HRESULT hr = m_graphBuilder->QueryInterface(IID_IVideoWindow, (void**)&pVideoWindow);
    if (pVideoWindow)
    {
        hr = pVideoWindow->put_Visible(show ? OATRUE : OAFALSE);
        SAFE_RELEASE(pVideoWindow);
    }
    return hr;
}

IVideoWindow* DShowGraph::queryVideoWindow()
{
    CheckPointer(m_graphBuilder, NULL);
    IVideoWindow* pVideoWindow = NULL;
    m_graphBuilder->QueryInterface(IID_IVideoWindow, (void**)&pVideoWindow);
    return pVideoWindow;
}

